練習完kotlin 協同程式 語法,那app就來試用看看吧
嫦娥跑跑 應用程式會模擬兩位參加賽跑的玩家。應用程式 UI 包含「Start」/「Pause」和「Reset」這兩個按鈕,以及兩條顯示玩家進度的進度列。玩家 1 和 2 將以不同速度「賽跑」。賽跑開始時,玩家 2 的跑步速度是玩家 1 的兩倍。

suspend fun run() {
    while (currentProgress < maxProgress) {
        delay(progressDelayMillis)
        currentProgress += progressIncrement
    }
}

使用 LaunchedEffect() 可組合函式,就能安全地從可組合函式呼叫暫停函式。
var raceInProgress by remember { mutableStateOf(false) }
    if (raceInProgress) {
        LaunchedEffect(playerOne, playerTwo) {
            launch {playerOne.run() }
            launch {playerTwo.run() }
        raceInProgress = false 
        }
    }
改用 coroutineScope
var raceInProgress by remember { mutableStateOf(false) }
   if (raceInProgress) {
       LaunchedEffect(playerOne, playerTwo) {
           coroutineScope {
               launch { playerOne.run() }
               launch { playerTwo.run() }
           }
           raceInProgress = false
       }
   }

suspend fun run() {
    try {
        while (currentProgress < maxProgress) {
            delay(progressDelayMillis)
            currentProgress += progressIncrement
        }
    } catch (e: CancellationException) {
        Log.e("RaceParticipant", "$name: ${e.message}")
        throw e // Always re-throw CancellationException.
    }
}
@Test
    fun raceParticipant_RaceStarted_ProgressUpdated() = runTest {
        val expectedProgress = 1
        launch { raceParticipant.run() }
        advanceTimeBy(raceParticipant.progressDelayMillis)
        runCurrent()
        assertEquals(expectedProgress, raceParticipant.currentProgress)
    }
    @Test
    fun raceParticipant_RaceFinished_ProgressUpdated() = runTest {
        launch { raceParticipant.run() }
        advanceTimeBy(raceParticipant.maxProgress * raceParticipant.progressDelayMillis)
        runCurrent()
        assertEquals(100, raceParticipant.currentProgress)
    }
    @Test
    fun raceParticipant_RacePaused_ProgressUpdated() = runTest {
        val expectedProgress = 5
        val racerJob = launch { raceParticipant.run() }
        advanceTimeBy(expectedProgress * raceParticipant.progressDelayMillis)
        runCurrent()
        racerJob.cancelAndJoin()
        assertEquals(expectedProgress, raceParticipant.currentProgress)
    }
    @Test
    fun raceParticipant_RacePausedAndResumed_ProgressUpdated() = runTest {
        val expectedProgress = 5
        repeat(2) {
            val racerJob = launch { raceParticipant.run() }
            advanceTimeBy(expectedProgress * raceParticipant.progressDelayMillis)
            runCurrent()
            racerJob.cancelAndJoin()
        }
        assertEquals(expectedProgress * 2, raceParticipant.currentProgress)
    }
    @Test(expected = IllegalArgumentException::class)
    fun raceParticipant_ProgressIncrementZero_ExceptionThrown() = runTest {
        RaceParticipant(name = "Progress Test", progressIncrement = 0)
    }
    @Test(expected = IllegalArgumentException::class)
    fun raceParticipant_MaxProgressZero_ExceptionThrown() {
        RaceParticipant(name = "Progress Test", maxProgress = 0)
    }
